<template>
  <div class="file-upload">
    <div
      class="file-upload-container"
      @click.prevent="triggerUpload"
      v-bind="$attrs"
    >
      <!-- 根据他的状态显示相应的效果 -->
      <slot v-if="fileStatus === 'loading'" name="loading">
        <button class="btn btn-primay">正在上传...</button>
      </slot>
      <slot
        v-else-if="fileStatus === 'success'"
        name="uploaded"
        :uploadedData="uploadedData"
      >
        <button class="btn btn-primay">上传成功</button>
      </slot>
      <slot name="default" v-else>
        <button class="btn btn-primay">点击上传</button>
      </slot>
    </div>

    <input
      type="file"
      class="file-input d-none"
      ref="fileInput"
      @change="handleFileChange"
    />
  </div>
</template>

<script lang="ts">
import axios from 'axios'
import { PropType, defineComponent, ref, watch } from 'vue'
// 设置状态
// 准备上传 上传中 上传成功 上传失败
type UploadStatus = 'ready' | 'loading' | 'success' | 'error'
// 设置 file 类型
type CheckFunction = (file: File) => boolean
export default defineComponent({
  props: {
    action: {
      type: String,
      required: true
    },
    beforeUpload: {
      type: Function as PropType<CheckFunction>
    },
    uploaded: {
      // 有了这个属性就可以初始化一些file了
      type: Object
    }
  },
  inheritAttrs: false,
  // 定义一个事件 成功和失败
  emits: ['file-uploade', 'file-uploade-error'],
  setup (props, context) {
    const fileInput = ref<null | HTMLInputElement>(null)
    // 声明状态
    const uploadedData = ref(props.uploaded)
    // 获取状态   是否在不在
    const fileStatus = ref<UploadStatus>(props.uploaded ? 'success' : 'ready')
    // 监听变化  第一个参数应该是响应式的
    watch(
      () => props.uploaded,
      (newValue) => {
        if (newValue) {
          fileStatus.value = 'success'
          uploadedData.value = newValue
        }
      }
    )
    // watch(
    //   () => props.uploaded,
    //   (newValue) => {}
    // )
    const triggerUpload = () => {
      // 判断 是否存在
      if (fileInput.value) {
        fileInput.value.click() // 给input绑定一个单击事件
      }
    }
    // 添加方法 监听input的改变
    const handleFileChange = (e: Event) => {
      const currentTarget = e.target as HTMLInputElement
      // 是否有这个值存在
      if (currentTarget.files) {
        fileStatus.value = 'loading'
        const files = Array.from(currentTarget.files)
        // 是否满足用户自定义的需求
        if (props.beforeUpload) {
          const result = props.beforeUpload(files[0])
          // 如果那个格式都不对就停止不走了
          if (!result) {
            return
          }
        }
        const formData = new FormData()
        formData.append('file', files[0])
        axios
          .post(props.action, formData, {
            headers: {
              'Content-Type': 'multipart/form-data'
            }
          })
          .then((resp) => {
            console.log(resp.data)
            fileStatus.value = 'success'
            // 赋值
            uploadedData.value = resp.data
            // 成功的时候触发
            context.emit('file-uploade', resp.data)
          })
          // 上传文件失败返回
          .catch((error) => {
            console.log(error)
            fileStatus.value = 'error'
            context.emit('file-uploade-error', { error })
          })
          .finally(() => {
            // 上传完毕 设置为空
            if (fileInput.value) {
              // 将文本框设置为空
              fileInput.value.value = ''
            }
          })
      }
    }
    return {
      fileInput,
      triggerUpload,
      fileStatus,
      handleFileChange,
      uploadedData
    }
  }
})
</script>

<style scoped></style>
